package com.gopay.cashier.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.manager.CustCorpInfoManager;
import com.gopay.cashier.service.SmsAcService;
import com.gopay.common.constants.cust.CustSmsAcConstants;
import com.gopay.common.constants.cust.CustSmsAcLogConstants;
import com.gopay.common.constants.cust.UserInfoConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.cust.CustCorpInfo;
import com.gopay.common.domain.cust.CustSmsAc;
import com.gopay.common.domain.cust.CustSmsAcLog;
import com.gopay.common.exception.GopayException;
import com.gopay.common.user.dao.CustSmsAcDAO;
import com.gopay.common.user.dao.CustSmsAcLogDAO;
import com.gopay.common.user.manager.CustCorpInfoQueryManager;
import com.gopay.common.user.manager.CustSmsAcManager;
import com.gopay.common.user.manager.UserInfoQueryManager;
import com.gopay.remote.user.UserRemoteService;
import com.gopay.sms.client.GopaySMSHttpClient;
import com.gopay.sms.common.constants.SMSAppId;
import com.gopay.sms.common.constants.SMSResCode;
import com.gopay.sms.common.domain.RequestVO;
import com.gopay.sms.common.domain.ResponseVO;

@Service("smsAcService")
public class SmsAcServiceImpl implements SmsAcService {

	private static final Logger logger = Logger.getLogger(GopaySMSHttpClient.class);

	@Resource(name = "custSmsAcDAO")
	private CustSmsAcDAO custSmsAcDAO;

	@Resource(name = "custSmsAcLogDAO")
	private CustSmsAcLogDAO custSmsAcLogDAO;

	@Resource(name = "userRemoteService")
	private UserRemoteService userRemoteService;

	@Resource(name = "custCorpInfoQueryManager")
	private CustCorpInfoQueryManager custCorpInfoQueryManager;

	@Resource(name = "custSmsAcManager")
	private CustSmsAcManager custSmsAcManager;

	@Resource(name = "custCorpInfoManager")
	private CustCorpInfoManager custCorpInfoManager;

	@Resource(name = "userInfoQueryManager")
	private UserInfoQueryManager userInfoQueryManager;

	/**
	 * 短信认证校验
	 * 
	 * @param loginUser
	 * @return
	 */
	public Map<String, String> getMapSmsAc(LoginUser loginUser) {
		Map<String, String> resMap = new HashMap<String, String>();

		// 操作员id
		String userType = loginUser.getUser().getUserType();
		String operId = loginUser.getUser().getOperId();
		if (!StringUtils.equals(userType, UserInfoConstants.USER_TYPE_PERSON.toString())) {
			CustCorpInfo custCorpInfo = custCorpInfoManager.get(loginUser.getUser().getCustId());
			CustSmsAc smsAc = custSmsAcManager.getCustSmsAcByCustId(loginUser.getUser().getCustId());
			// 管理员
			if (StringUtils.equals(loginUser.getUser().getOperId(), UserInfoConstants.CORP_ADMIN_CODE)) {

				// 判断当前管理的短信认证状态是锁定
				if (StringUtils.equals(smsAc.getSmsAcLockStat(), CustSmsAcConstants.SMSAC_LOCKED)) {
					resMap.put("error_msg", "短信验证功能已被锁定，请联系我司客服：400-0550-009");
					resMap.put("error", "error");

				}
			}
			if (StringUtils.equals(userType, UserInfoConstants.USER_TYPE_CORP_ADMIN)) {
				if (loginUser.getUser().getCustId() != null) {
					if (custCorpInfo.getCustMob() != null) {
						// 企业管理员手机号
						resMap.put("custMob", custCorpInfo.getCustMob());
					}
				}
			} else {
				UserInfo userInfo = userInfoQueryManager.getUserInfoByUserId(loginUser.getUser().getUserId());

				// 财务人员校验

				CustSmsAc custSmsAc = custSmsAcDAO.getCustSmsAcByUserId(loginUser.getUser().getUserId());
				if (custSmsAc != null) {
					if (StringUtils.equals(userInfo.getUserStat(), UserInfoConstants.USER_STAT_LOCKED)
							|| StringUtils.equals(smsAc.getSmsAcLockStat(), CustSmsAcConstants.SMSAC_LOCKED)) {
						resMap.put("error_msg", "短信验证功能已被锁定，请联系您的管理员");
						resMap.put("error", "error");

					}
					// 财务人员
					if (!StringUtils.equals(loginUser.getUser().getOperId(), UserInfoConstants.CORP_ADMIN_CODE)
							&& custSmsAc.getTodaySmsErrNum() == 5) {
						resMap.put("error_msg", "验证码连续错误5次，当前操作员已被锁定，请联系管理员为您解锁。");
						resMap.put("error", "error");

					}
					if (userInfo.getOperMobile() != null) {
						// 财务人员手机号
						resMap.put("custMob", userInfo.getOperMobile());
						loginUser.getUser().setOperMobile(userInfo.getOperMobile());
					} else {
						resMap.put("error_msg", "您的验证手机还未绑定，请联系管理员为您添加。若您已完成手机绑定，请点击“获取短信验证码”");
						resMap.put("error", "error");
					}
				}
			}

		}

		return resMap;

	}

	// public void commonSmsAcValiErrTips() throws GopayException {
	// OprInfo oprInfo = (OprInfo) SecurityUtils.getSubject().getPrincipal();
	// boolean result = CustSmsAcConstants.SMSAC_LOCKED
	// .equals(custSmsAcManager.getCustSmsLockStatByCustId(oprInfo.getCustId()))
	// && getTodaySmsErrNum(oprInfo.getUserId()) < 5;
	// boolean isAdmin =
	// UserInfoConstants.CORP_ADMIN_CODE.equals(oprInfo.getOperId());
	// if (result) {// 控制台锁定
	// throw new GopayException(ProcCodeConstants.PROC_CODE_100E8006,
	// isAdmin ? "短信验证功能已被锁定，请联系我司客服：400-0550-009。" : "短信验证功能已被锁定，请联系您的管理员。");
	// } else { // 正常锁定 次数等于5
	// throw new GopayException(ProcCodeConstants.PROC_CODE_100E8006,
	// isAdmin ? "验证码连续错误5次，短信验证功能已被锁定，请联系我司客服：400-0550-009。" :
	// "验证码连续错误5次，当前操作员已被锁定，请联系管理员为您解锁。");
	// }
	// }

	/**
	 * @Description: 生成短信提示
	 * @param mobile
	 *            手机号码
	 * @param bizCode
	 *            业务码
	 * @return
	 * @author lx
	 */
	@Override
	public String getMsmSendTIps(String mobile) {
		// 已向您的手机152xxxx1535发送了短信验证码，请您查收，验证码3分钟内有效。
		StringBuilder sb = new StringBuilder();
		sb.append("已向您的手机");
		sb.append(toEncryptMobile(mobile));
		sb.append("发送了短信验证码，请您查收，验证码");
		sb.append("3");
		sb.append("分钟内有效。");
		return sb.toString();
	}

	/**
	 * 描述：手机号码加密
	 * 
	 * <pre>
	 * 加密前：18201631234 加密后：182****1234 </per> 时间：2016年5月10日 下午5:11:09
	 * </pre>
	 * 
	 * @author : lx
	 * @param mobile
	 * @return String
	 */
	public final static String toEncryptMobile(String mobile) {
		return mobile.substring(0, 3) + "****" + mobile.substring(7, 11);
	}

	public void checkPayPwdAndVerifyCode(LoginUser loginuser, String verifyCode) throws GopayException {
		ResponseVO response = null;
		if (StringUtils.isBlank(verifyCode)) {
			logger.error("短信认证，短信验证失败原因:验证码不能为空。");
			// 不成功抛异常，输出错误短息内容
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E8006, "验证码不能为空");
		}
		verifyCode = verifyCode.trim();
		if (verifyCode.length() < 6) {
			logger.error("短信认证，短信验证失败原因:短信验证码格式不正确。");
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E8006, "短信验证码格式不正确");
		}
		// 验证短信验证码
		response = valiSms(loginuser, verifyCode);

		if (!SMSResCode.SMS_VERIFY_SUCCESS.value.equals(response.getStatusCode())) {
			logger.error("短信认证，短信验证失败原因:" + response.getMessage());
			// 不成功抛异常，输出错误短息内容
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E8006, response.getMessage());
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
	public ResponseVO valiSms(LoginUser loginuser, String verifyCode) throws GopayException {
		String userId = loginuser.getUser().getUserId();
		String custId = loginuser.getUser().getCustId();
		ResponseVO response = null;
		// 获取错误次数
		CustSmsAc custSmsAc = custSmsAcDAO.getCustSmsAcByUserId(userId);
		UserInfo userInfo = userInfoQueryManager.get(userId); // 获取用户信息
		if (custSmsAc == null) {
			return null;
		}

		int todayErrNum = custSmsAc.getTodaySmsErrNum(); // 错误次数
		Map<String, String> resMap = getMapSmsAc(loginuser);// 获取手机号
		
		if (StringUtils.isNotBlank(resMap.get("error_msg"))) {
			response=new ResponseVO();
			response.setMessage(resMap.get("error_msg").toString());
			return response;
		}

		// 验证的前提：锁定开启状态 正常 且 错误次数小于5次
		if (valiCustSmsAcStatByCustId(custId) && todayErrNum < 5) {
			// 验证短信状态,根据业务码判断超时时间
			/*
			 * ResponseVO response =
			 * portalSendSMSService.mobileActivateCodeTime(mobileNo, verifyCode,
			 * SMSAppId._90001.value, SmsAcUtil.getBizMsmOutTime(bizCode));
			 */
			RequestVO req = new RequestVO();
			req.setAppId(SMSAppId._10074.value);
			req.setMobile(resMap.get("custMob"));
			req.setCode(verifyCode);
			req.setUserId(userId);
			req.setTimeout("180");

			response = GopaySMSHttpClient.getInstance().verifyCode(req);
			if (response == null) {
				throw new GopayException(ProcCodeConstants.PROC_CODE_100E8006, "短信网关状态异常");
			}
			

			// 验证错误
			if (!SMSResCode.SMS_VERIFY_SUCCESS.value.equals(response.getStatusCode())) {
				// 如果错误 次数 +1
				todayErrNum = todayErrNum + 1;
				if (todayErrNum == 5) {
					// 短信认证锁定状态参数设置
					custSmsAc.setLockSmsAcTime(new Date());
					custSmsAc.setLastUpdTs(new Date());
					// 认证锁定日志参数设置
					CustSmsAcLog custSmsAcLog = new CustSmsAcLog();
					custSmsAcLog.setCreateTs(new Date());
					custSmsAcLog.setLastUpdTs(new Date());
					custSmsAcLog.setCustId(custId);
					custSmsAcLog.setUserId(userId);
					custSmsAcLog.setOperId(loginuser.getUser().getOperId());
					custSmsAcLog.setOperType("03");
					custSmsAcLog.setOperContent(CustSmsAcLogConstants.OPER_CONTENT_011);

					if (UserInfoConstants.CORP_ADMIN_CODE.equals(userInfo.getOperId())) {
						// 管理员 短信认证状态锁定
						custSmsAc.setSmsAcLockStat(CustSmsAcConstants.SMSAC_LOCKED);// 设置状态锁定
					} else {
						// 其他操作员 USER INFO 锁定
						userInfo.setUserStat(UserInfoConstants.USER_STAT_LOCKED);
						userInfo.setLastUpdTs(new Date());
						userRemoteService.editUserInfo(userInfo);// 更新用户信息
					}

					updateErrNumAndStatus(custSmsAc, todayErrNum);// 更新短信认证表
					custSmsAcLogDAO.save(custSmsAcLog);// 插入操作日志记录
				} else {
					// 验证码错误 ，剩余错误次数
					updateErrNumAndStatus(custSmsAc, todayErrNum);// 错误次数清零

				}
				String errTips = getMsmValiErrTips(todayErrNum, loginuser);
				response.setMessage(errTips);
				return response;
			} else {
				// 验证成功直接返回
				if (todayErrNum != 0) {
					updateErrNumAndStatus(custSmsAc, 0);// 错误次数清零
				}

				return response;
			}
		}
		return response;// 锁定提示
	}

	/**
	 * @Description:修改状态和错误次数,更新短信认证记录
	 * @param custSmsAc
	 * @param errNum
	 * @author lx
	 */
	private void updateErrNumAndStatus(CustSmsAc custSmsAc, int errNum) {
		custSmsAc.setTodaySmsErrNum(errNum);// 设置错误次数;
		custSmsAcDAO.update(custSmsAc);
	}

	/**
	 * @Description: 短信验证锁定提示
	 * @param userInfo
	 * @param responseVO
	 * @author lx
	 */
	public ResponseVO msmLockedTips(UserInfo userInfo, ResponseVO responseVO) throws GopayException {
		responseVO.setStatusCode("999");
		if (UserInfoConstants.CORP_ADMIN_CODE.equals(userInfo.getOperId())) {
			responseVO.setMessage("验证码连续错误5次，短信验证功能已被锁定，请联系我司客服：400-0550-009。");

		} else {
			responseVO.setMessage("短信验证功能已被锁定，请联系您的管理员。");
		}

		return responseVO;
	}

	/**
	 * @Description: 生成短信错误提示
	 * @param num
	 *            错误次数
	 * @return
	 * @author lx
	 */
	public static final String getMsmValiErrTips(int num, LoginUser loginuser) {
		// “验证码错误，还有x次机会（当天错误次数达到5次时, 短信验证功能将被锁定）”
		int total = 5;// 当日可以错误的总次数
		StringBuilder sb = new StringBuilder();
		sb.append("验证码错误，");
		if (total > num) {
			sb.append("还有");
			sb.append(total - num);
			sb.append("次机会（连续错误次数达到5次时, ");
			if (UserInfoConstants.CORP_ADMIN_CODE.equals(loginuser.getUser().getOperId())) {
				sb.append("短信验证功能");
			} else {
				sb.append("当前操作员");
			}
			sb.append("将被锁定）");
		} else {
			if (UserInfoConstants.CORP_ADMIN_CODE.equals(loginuser.getUser().getOperId())) {
				sb.append("验证码连续错误5次，短信验证功能已被锁定，请联系我司客服：400-0550-009。");
			} else {
				sb.append("验证码连续错误5次，当前操作员已被锁定，请联系管理员为您解锁。");
			}
		}
		return sb.toString();
	}

	public boolean valiCustSmsAcStatByCustId(String custId) {
		CustCorpInfo custCorpInfo = custCorpInfoQueryManager.getByCustId(custId);
		if (custCorpInfo != null && StringUtils.isNotBlank(custCorpInfo.getSmsAcStat())) {
			if (CustSmsAcConstants.SMSAC_OPEN.equals(custCorpInfo.getSmsAcStat())) {// 判断企业是否开启短信认证
				// String status =
				// custSmsAcManager.getCustSmsLockStatByCustId(custId);
				// return StringUtils.isNotBlank(status) &&
				// CustSmsAcConstants.SMSAC_UNLOCK.equals(status);//
				// 判断企业短信认证状态是否正常
				return true;
			}

			logger.info("企业{}短信认证状态锁定" + custId);
			return false;
		}

		logger.info("企业{}短信认证状态未开启" + custId);
		return false;
	}

	public int getTodaySmsErrNum(String userId) {
		// 获取错误次数
		CustSmsAc custSmsAc = custSmsAcDAO.getCustSmsAcByUserId(userId);
		return custSmsAc.getTodaySmsErrNum();
	}

	@Override
	public boolean canSendSms(LoginUser loginUser) {
		return valiCustSmsAcStatByCustId(loginUser.getUser().getCustId());
	}
	// && getTodaySmsErrNum(loginUser.getUser().getUserId()) < 5

	public ResponseVO getSmsLockedTips(LoginUser loginUser, ResponseVO response) throws GopayException {
		UserInfo userInfo = userInfoQueryManager.get(loginUser.getUser().getUserId());
		return msmLockedTips(userInfo, response);
	}

	@Override
	public ResponseVO sendBizSMSAc(RequestVO req, String userId) {
		// 根据业务码 获取短信内容 并设置短信内容
		req.setContent("您正在使用国付宝账户进行支付，验证码为：%s。【请勿泄露】如有疑问请致电：400-055-0009。感谢您使用国付宝支付服务！");

		return GopaySMSHttpClient.getInstance().createVerificationCode(req);
	}

	@Override
	public Map<String, String> getSmsAc(LoginUser loginUser) {
		Map<String, String> map = new HashMap<String, String>();
		// 操作员id
		String userType = loginUser.getUser().getUserType();
		String operId = loginUser.getUser().getOperId();
		if (!StringUtils.equals(userType, UserInfoConstants.USER_TYPE_PERSON.toString())) {
			CustCorpInfo custCorpInfo = custCorpInfoManager.get(loginUser.getUser().getCustId());
			if (StringUtils.equals(userType, UserInfoConstants.USER_TYPE_CORP_ADMIN)
					&& StringUtils.equals(operId, UserInfoConstants.CORP_ADMIN_CODE)) {
				if (loginUser.getUser().getCustId() != null) {
					// 企业管理员手机号
					map.put("custMob", custCorpInfo.getCustMob());
				}
			} else {
				// 财务人员手机号
				map.put("custMob", loginUser.getUser().getOperMobile());
			}
			map.put("smsAcStat", custCorpInfo.getSmsAcStat());
			map.put("userId", loginUser.getUser().getUserId());
			// 用户类型
			map.put("userType", userType);
		}
		return map;
	}

}
